package de.g18.it0a.jlaser.domain;

import java.util.ArrayList;
import java.util.List;

import de.g18.it0a.jlaser.exception.IllegalPositionException;


public final class Tile {

    private final Position position;

    private final int width;
    private final int height;

    private List<Fixture> fixtures;


    public Tile(Position aPosition, int aWidth, int aHeight) {
        position = aPosition;
        width = aWidth;
        height = aHeight;
        fixtures = new ArrayList<Fixture>();
    }

    public Position getPosition() {
        return position;
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

    public void addFixture(Fixture aFixture) throws IllegalPositionException {
        if (!canFixtureBePlaced(aFixture)) {
            throw new IllegalPositionException(aFixture + " can not be placed at " + aFixture.getPosition() + " (" + this + ") ", aFixture.getPosition());
        }
        fixtures.add(aFixture);
    }

    private boolean canFixtureBePlaced(Fixture aFixture) {
        Position relativPosition = new Position(aFixture.getPosition().getX() - getPosition().getX(),
                                                aFixture.getPosition().getY() - getPosition().getY());
        int maxFixtureX = (int) (relativPosition.getX() + aFixture.getRepresentation().getBounds2D().getMaxX());
        int maxFixtureY = (int) (relativPosition.getY() + aFixture.getRepresentation().getBounds2D().getMaxY());
        if (relativPosition.getX() < 0 || relativPosition.getY() < 0
             || maxFixtureX > getWidth() || maxFixtureY > getHeight()) {
            return false;
        }

        if (aFixture.isSolid()) {
            for (Fixture fixture : getSolidFixtures()) {
                if (fixture.getRepresentation().intersects(aFixture.getRepresentation().getBounds2D())) {
                    return false;
                }
            }
        }
        return true;
    }

    public List<Fixture> getFixtures() {
        return fixtures;
    }

    public boolean containsSolidFixtures() {
        return !getSolidFixtures().isEmpty();
    }

    public List<Fixture> getSolidFixtures() {
        List<Fixture> solidFixtures = new ArrayList<Fixture>();
        for (Fixture fixture : getFixtures()) {
            if (fixture.isSolid()) {
                solidFixtures.add(fixture);
            }
        }
        return solidFixtures;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (fixtures == null ? 0 : fixtures.hashCode());
        result = prime * result + height;
        result = prime * result + (position == null ? 0 : position.hashCode());
        result = prime * result + width;
        return result;
    }

    @Override
    public boolean equals(Object aObject) {
        if (aObject == this) {
            return true;
        }
        if (aObject == null) {
            return false;
        }
        if (!(aObject instanceof Tile)) {
            return false;
        }

        Tile other = (Tile) aObject;
        return getWidth() == other.getWidth()
                && getHeight() == other.getHeight()
                && getPosition().equals(other.getPosition())
                && getFixtures().equals(other.getFixtures());
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + "[width=" + getWidth()
                                          + ",height=" + getHeight()
                                          + ",position=" + getPosition()
                                          + ",fixtures=" + getFixtures().size()
                                          + ",containsSolidFixtures=" + containsSolidFixtures() + "]";
    }
}
